#pragma once

#include "Stroke.h"
#include "OrientedArc.h"
#include "NeighborEnumerator.h"
#include <map>
#include <deque>

extern const int kInvalidIndex;

// forward declarations
class NeighborEnumerator;
class DistinctivePoint;
struct Junction;

// This class looks for vertexes amid the stroke (they are obtuse angles)
// and for the T-points as intercection of the other stroke 
// approaching the middle of the current stroke.
// This class is a friend of the Stroke class and accesses it's member 
// variable mDots.
class StrokeVertexesFinder
{
	// weak links
	//const Stroke& mStroke;
	//NeighborEnumerator& mNeighborEnumerator;

	//int mCurrentIndex;
	//const int mDotsCount;
	//const Stroke::ConstDotIterator mBegin;
	//const Stroke::ConstDotIterator mEnd;
	//Stroke::ConstDotIterator mCurrentIterator;

	//bool mWasTPointFound;

	//float mPrevVx, mPrevVy, mPrevScalarProduct;

	//----------
	struct ArcInfo {
		const NeighborEnumerator::Info* info;
		OrientedArc arc; int firstIndex, lastIndex, indexT;
		

		ArcInfo(const NeighborEnumerator::Info* inInfo)
			:	info(inInfo),
				arc(*(info->dot), Stroke::kBeforeFront == info->strokeEnd),
				firstIndex(kInvalidIndex), 
				lastIndex(kInvalidIndex), 
				indexT(kInvalidIndex)
		{
		}
	};
	
	struct TPointInfo { 
		const ArcInfo* arcInfo;
		Curve curve;
		float x, y, t, s;
		bool isDeleted;
	};
	struct TwoEndsInfo {
		ArcInfo *arcInfo1, *arcInfo2;
		float x, y, s1, s2;
		int next1, next2;
		bool isDeleted;

		// helper functions
		inline int NextIndexFor(const ArcInfo*) const;
		inline bool DeleteIfSmallerParameter(const ArcInfo*, 
			float parameterLimit);
	};
	struct CornerInfo
	{
		const ContourDot *dot1, *dot2;
		float x, y;
		const Stroke* stroke;
		int index1, index2;
	};
	typedef std::pair<ArcInfo*, ArcInfo*> JunctionInfo;

	typedef std::map<const NeighborEnumerator::Info*, ArcInfo*> InfoMap;
	typedef std::deque<TPointInfo> TPointCollection;
	typedef std::deque<JunctionInfo> JunctionCollection;
	typedef std::deque<CornerInfo> CornerCollection;

	NeighborEnumerator& mNeighborEnumerator; // weak link

	// note that other collections also contain weak links to NeighborEnumerator
	std::deque<ArcInfo> mArcInfos;
	InfoMap mMap;
	TPointCollection mTPointInfos;
	std::deque<TwoEndsInfo> mTwoEndsInfos;
	JunctionCollection mJunctions;
	CornerCollection mCorners;
	float mLimitForArcParameter;
	float mSavedScalarProducts[4];

	// a variable is used for calculation of total number of distinctive points
	int mNumberOfDiscardedVertexes;

public:
	StrokeVertexesFinder(NeighborEnumerator&);
	void AddVertexesForStrokeEnds(const Stroke&);
	void AddVertexesForStroke(const Stroke&);
	void PruneMultipleIntersections();
	int GetNumberOfVertexes() const;
	void GetVertexes(DistinctivePoint* outBuffer) const;

	int GetNumberOfJunctions() const;
	void GetJunctions(Junction* outBuffer) const;


	//StrokeVertexesFinder(const Stroke&, NeighborEnumerator&);
	//bool FindNextVertex(DistinctivePoint&);

private:
	void AddTPoints(const Curve&);
	void AddCorner(const ContourDot* prev3, const ContourDot* prev2,
		const ContourDot* prev1, const ContourDot* dot, 
		const Stroke& stroke, int index);
	void AddEndsMeeting(const Stroke&, int strokeEnd);
	ArcInfo* GetArcInfoBuiltOn(const NeighborEnumerator::Info* info);

	DistinctivePoint* GetTPoints(DistinctivePoint* ioBuffer) const;
	DistinctivePoint* GetEndsMeetings(DistinctivePoint* ioBuffer) const;
	DistinctivePoint* GetCorners(DistinctivePoint* ioBuffer) const;

	void AddDirectionToDistinctivePoint(DistinctivePoint&, 
		const ArcInfo& fromInfo, float x, float y) const;

	inline float GetSavedScalarProduct(int index) const;

	//bool FindIntersection(const Stroke* otherStroke, int otherStrokeEnd, 
	//	DistinctivePoint& outPoint);
	//bool CheckAngle(DistinctivePoint& outPoint);
	//void SetCornerTo(DistinctivePoint& outPoint, bool skipCurrentDot);
};

